package com.x52im.rainbowchat.http.logic.pay.redenvelope;

import com.alibaba.fastjson.JSON;
import com.eva.epc.common.util.CommonUtils;
import com.eva.framework.dbpool.DBDepend;
import com.eva.framework.utils.LoggerFactory;
import com.x52im.rainbowchat.http.dao.MoneyDAO;
import com.x52im.rainbowchat.http.logic.LogicUtils;
import com.x52im.rainbowchat.http.logic.dto.AccountDTO;
import com.x52im.rainbowchat.http.logic.dto.RedEnvelopeDTO;
import com.x52im.rainbowchat.http.util.JedisTools;
import com.x52im.rainbowchat.http.util.RedissonTools;
import org.redisson.api.RLock;

import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 抢红包
 */
public class MRedEnvelopeGetFromRedis extends ARedEnvelope {
    @Override
    public String deal(RedEnvelopeDTO dto) throws Exception {
        long nt = System.nanoTime();
        List<RedEnvelopeDTO> envelopes = moneyDAO.queryRedEnvelopsRoot(dto, true);

        // 如果已经领取过则返回领取了的红包
        RedEnvelopeDTO findedDTO = finded(envelopes, dto);
        if (findedDTO != null) {
            LoggerFactory.getLog().info(String.format("【%s】findedDTO, %s", nt, findedDTO));
            return JSON.toJSONString(findedDTO);
        }

        String check = check(envelopes, dto);
        if (check != null) {
            LoggerFactory.getLog().info(String.format("【%s】check, %s", nt, check));
            return check;
        }

        boolean finishAllAfterThistime = false;  // 本次取红包后全部红包都取完了

        String getId = null;
        String getAmount = null;
        String redisKey = RedEnvelopeDTO.getRedisKey(dto.getId());
        String lockKey = RedEnvelopeDTO.getRedisKeyForLock(dto.getId());
        RLock lock = RedissonTools.redisson.getLock(lockKey);
        LoggerFactory.getLog().info(String.format("【%s】获取 lock, %s", nt, lock.getName()));
        boolean getLock = false;
        try {
            getLock = lock.tryLock(3, 10, TimeUnit.SECONDS);
            if (getLock) {
                String ids = JedisTools.getDB(redisKey, RedEnvelopeDTO.REDIS_DB_INDEX);
                if (!CommonUtils.isStringEmpty(ids)) {
                    String[] idandamounts = ids.split(",");
                    String idAndAmount = idandamounts[0];   // 取第一个红包,或者改成随机取一个元素
                    String[] idAndAmounts = idAndAmount.split("-");
                    getId = idAndAmounts[0];
                    getAmount = idAndAmounts[1];

                    Vector sqls = new Vector();
                    Vector values = new Vector();
                    // 更新红包状态
                    sqls.add("UPDATE missu_red_envelope SET user_uid=?, state=?, memo=?, state_date=? WHERE id=?");
                    values.add(new Object[]{dto.getUserUid(), RedEnvelopeDTO.STATE.STATE_FINISH.getState(), RedEnvelopeDTO.STATE.STATE_FINISH.getStateMemo(), new Date(), getId});
                    // 更新账户余额
                    int ranodmMoney = Integer.parseInt(getAmount);
                    String _total = db.querySingleItem("total", "missu_account", "user_uid=" + dto.getUserUid());
                    int total = Integer.parseInt(_total);
                    int totlaNew = total + ranodmMoney;
                    sqls.add("UPDATE missu_account SET total=?, state_date=? WHERE user_uid=?");
                    values.add(new Object[]{totlaNew, new Date(), dto.getUserUid()});
                    boolean update = db.update(sqls, values, true);
                    if (update) {
                        sqls.clear();
                        values.clear();

                        // 插入账户历史表
                        sqls.add("INSERT INTO missu_account_his(user_uid,total,`type`,type_id,change_amount) VALUES(?,?,?,?,?)");
                        values.add(new Object[]{dto.getUserUid(), totlaNew, AccountDTO.TYPE_FOR_RED_ENVELOP_GET, getId, getAmount});

                        if (idandamounts.length == 1) {
                            // 领完了
                            sqls.add("UPDATE missu_red_envelope SET state=?, memo=?, state_date=? WHERE id=?");
                            values.add(new Object[]{RedEnvelopeDTO.STATE.STATE_FINISH_ALL.getState(), RedEnvelopeDTO.STATE.STATE_FINISH_ALL.getStateMemo(), new Date(), dto.getId()});
                            boolean broot = db.update(sqls, values, true);
                            if (broot) {
                                finishAllAfterThistime = true;
                            }
                        } else {
                            db.update(sqls, values, true);

                            // 去除第一个红包
                            String newIdAndAmounts = Arrays.stream(idandamounts).skip(1).collect(Collectors.joining(","));
                            JedisTools.setDB(redisKey, newIdAndAmounts, RedEnvelopeDTO.REDIS_DB_INDEX);
                        }
                    }
                }
            }
        } catch (Exception e) {
            throw new Exception(String.format("抢红包异常::%s", e.getMessage()));
        } finally {
            if (getLock) {
                LoggerFactory.getLog().info(String.format("【%s】释放 lock, %s", nt, lock.getName()));
                RedissonTools.redisson.getLock(lockKey).unlock();
            }
        }

        if (finishAllAfterThistime) {
            JedisTools.delkeyObjectDB(redisKey, RedEnvelopeDTO.REDIS_DB_INDEX);
        }

        RedEnvelopeDTO getDTO = null;
        if (!CommonUtils.isStringEmpty(getId)) {
            getDTO = moneyDAO.queryRedEnvelop(getId);
        } else {
            getDTO = new RedEnvelopeDTO();
            getDTO.setUNKNOWED("红包已经被领完了");
        }
        return JSON.toJSONString(getDTO.toMap());
    }

    /**
     * 获取已经领取的红包
     *
     * @param envelopes
     * @param dto
     * @return
     */
    private RedEnvelopeDTO finded(List<RedEnvelopeDTO> envelopes, RedEnvelopeDTO dto) {
        if (envelopes == null || envelopes.isEmpty()) {
            return null;
        }
        RedEnvelopeDTO rootEnvelope = envelopes.get(0);
        List<RedEnvelopeDTO> subs = rootEnvelope.getSubRedEnvelopeDTOS();
        Optional<RedEnvelopeDTO> finded = subs.stream().filter(redEnvelope1 -> !CommonUtils.isStringEmpty(redEnvelope1.getUserUid())
                && redEnvelope1.getUserUid().equals(dto.getUserUid())).findFirst();
        RedEnvelopeDTO foundEnve = finded.orElse(null);
        return foundEnve;
    }

    /**
     * 校验
     *
     * @param dto
     * @param envelopes
     * @return
     * @throws Exception
     */
    private String check(List<RedEnvelopeDTO> envelopes, RedEnvelopeDTO dto) throws Exception {
        if (envelopes == null || envelopes.isEmpty()) {
            dto.setUNKNOWED("找不到红包");
            return JSON.toJSONString(dto);
        }
        RedEnvelopeDTO rootEnvelope = envelopes.get(0);
        if (!rootEnvelope.getParentId().equals("-1")) {
            dto.setUNKNOWED("请传入根红包ID");
            return JSON.toJSONString(dto);
        }
        if (rootEnvelope.getState().equals(RedEnvelopeDTO.STATE.STATE_FINISH_ALL.getState())) {
            dto.setFINISHAll();
            return JSON.toJSONString(dto);
        }
        if (!rootEnvelope.getUserUid().equals(dto.getUserUid())) {
            if (!CommonUtils.isStringEmpty(dto.getgId())) {
                boolean inSameGroup = LogicUtils.inSameGroup(dto.getUserUid(), rootEnvelope.getUserUid(), rootEnvelope.getgId());
                if (!inSameGroup) {
                    dto.setUNKNOWED("不同群不能领取红包");
                    return JSON.toJSONString(dto);
                }
            } else {
                boolean isFriend = LogicUtils.isFriend(dto.getUserUid(), rootEnvelope.getUserUid());
                if (!isFriend) {
                    dto.setUNKNOWED("非好友不能领取红包");
                    return JSON.toJSONString(dto);
                }
            }
        }
        String redisKey = RedEnvelopeDTO.getRedisKey(dto.getId());
        boolean exists = JedisTools.existsObjectDB(redisKey, RedEnvelopeDTO.REDIS_DB_INDEX);
        if (!exists) {
            dto.setUNKNOWED("找不到红包");
            return JSON.toJSONString(dto);
        }

        return null;
    }

}
